<!DOCTYPE html>
<html lang="en">
<head>
    <title>囧么肥事</title>
    <meta charset="UTF-8"/>
    <meta name="viewport"
          content="width=device-width,height=device-height,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta http-equiv="Content-Type" content="text/html;"/>
    <meta name="renderer" content="webkit">
    <!--解决页面加载网络图片的403问题 , 可以让img标签预加载网络图片-->
    <meta name="referrer" content="no-referrer" />

    <!--markdown S -->
    <link rel="stylesheet" type="text/css" href="../../static/css/export_setting_css.css"/>
    <link rel="stylesheet" type="text/css" href="../../static/css/markdown_preview_css.css"/>
    <!--markdown E -->

    <!--left bar tools css E-->
    <link rel="stylesheet" type="text/css" href="../../static/css/nav.css">
    <link rel="stylesheet" type="text/css" href="http://www.jq22.com/jquery/font-awesome.4.6.0.css">
    <!--left bar tools css E-->

    <!-- 滚动条 S -->
    <link rel="stylesheet" href="../../static/css/optiscroll.css">
    <!-- 滚动条 E -->
</head>
<body>
<div id="m-wrapper" class="m-wrapper optiscroll">
    <!-- top 锚点 -->
    <a id="top"></a>

    <!-- left bar tools S -->
    <div class="leftNav-item">
        <ul>
            <li>
                <i class="fa fa-location-arrow"></i>
                <a href="http://jiongmefeishi.gitee.io/monster-blog/" target="_blank" class="rota">个人网站</a>
            </li>

            <li title="Git">
                <i class="fa fa-code-fork" aria-hidden="true"></i>
                <a href="http://jiongmefeishi.gitee.io/monster-blog/" target="_blank" class="rota">Git Page</a>
            </li>

            <li lay-data="img" data-fooc="http://resource.zqtaotao.cn/wx/qrcode/jiongmefeishi.jpg">
                <i class="fa fa-comments-o"></i><a href="javascript:;" class="rota">公众号</a>
            </li>

            <li lay-data="img" data-fooc="http://resource.zqtaotao.cn/weixincode.png">
                <i class="fa fa-money"></i><a href="javascript:;" class="rota">小额打赏</a>
            </li>
            <li title="返回顶部" class="for-top">
                <i class="fa fa-arrow-up"></i>
                <a href="#top" class="rota">去顶部</a>
            </li>
        </ul>
    </div>
    <!-- left bar tools E -->

    <!--content S-->
    <div id="export_content"><div class="output_wrapper" id="output_wrapper_id"><h3 id="hk8sstatefulsetspod"><span>k8s集群StatefulSets的Pod优雅调度问题思考？</span></h3>
        <pre><code class="hljs">考点之你能解释一下为什么k8s的&nbsp;StatefulSets&nbsp;需要VolumeClaimTemplate嘛？<br></code></pre>
        <pre><code class="hljs">考点之简单描述一下StatefulSets&nbsp;对Pod的编排调度过程？<br></code></pre>
        <pre><code class="hljs">考点之针对线上StatefulSet&nbsp;的Pod缩容故障无法正常缩容的情况，你能灰度分析一下嘛？<br></code></pre>
        <pre><code class="hljs">考点之聊聊什么是StatefulSet的分区滚动更新吧？什么场景需要使用分区更新？<br></code></pre>
        <pre><code class="hljs">考点之StatefulSet提供优雅稳定的存储，但是线上告警StatefulSet&nbsp;Pod重新调度后数据丢失？<br></code></pre>
        <figure><img src="https://img-blog.csdnimg.cn/img_convert/d660a4b491b226f527b7e86cacaeea8e.gif" alt="" title=""><figcaption></figcaption></figure>
        <h3 id="h"><span>囧么肥事-胡说八道</span></h3>
        <figure><img src="https://img-blog.csdnimg.cn/img_convert/2703a664ae7c0bcb1909a80e5150a654.png" alt="" title=""><figcaption></figcaption></figure>
        <figure><img src="https://img-blog.csdnimg.cn/img_convert/012a99abe16dba0987d1bb850ec8b4b1.png" alt="" title=""><figcaption></figcaption></figure>
        <figure><img src="https://img-blog.csdnimg.cn/img_convert/7243248884e6177a1af7193e167c1d6a.png" alt="" title=""><figcaption></figcaption></figure>
        <h3 id="hk8sstatefulsetsvolumeclaimtemplate"><span>你能解释一下为什么k8s的 StatefulSets 需要VolumeClaimTemplate嘛？</span></h3>
        <p>对于k8s集群来说有状态的副本集都会用到<strong>持久存储</strong>。</p>
        <p><code>Deployment</code>中的<code>Pod template</code>里定义的存储卷，是<strong>基于模板配置调度</strong>，<strong>所有副本集共用一个存储卷</strong>，数据是相同的。</p>
        <p><code>StatefulSet</code>职责是管理<strong>有状态应用</strong>，所以它管理的每个<code>Pod</code>都要自已的<strong>专有存储卷</strong>，它的存储卷就不能再用Pod模板来创建。</p>
        <p>所以 <code>StatefulSets</code> 需要一种新方式来为管辖的<code>Pod</code>分配存储卷。</p>
        <p>就这样<code>VolumeClaimTemplate</code>来了，<code>k8s</code> 给 <code>StatefulSets</code> 设置了<code>VolumeClaimTemplate</code>，也就是<strong>卷申请模板</strong>。</p>
        <p><strong>说了为什么需要它，那么VCT到底是什么呢？</strong></p>
        <p><code>VolumeClaimTemplate</code>：基于<strong>静态或动态</strong>地PV供给方式为Pod资源提供<strong>专有且固定的存储</strong>，它会为每个Pod都生成不同的<code>PVC</code>，并且绑定PV，实现每个Pod都有自己独立专用的存储卷。</p>
        <h3 id="hstatefulsetspod"><span>简单描述一下StatefulSets 对Pod的编排调度过程？</span></h3>
        <p>StatefulSets 提供了<strong>有序且优雅的部署和扩缩保证</strong>。</p>
        <p>SS是如何优雅部署和扩缩的呢？</p>
        <p>对于包含 N 个 副本的 StatefulSet</p>
        <pre><code class="hljs css">当部署&nbsp;<span class="hljs-selector-tag">Pod</span>&nbsp;时，它们是依次创建的，顺序为&nbsp;`0.<span class="hljs-selector-class">.N-1</span>`。<br><br>当删除&nbsp;<span class="hljs-selector-tag">Pod</span>&nbsp;时，它们是逆序终止的，顺序为&nbsp;`<span class="hljs-selector-tag">N-1</span>.<span class="hljs-selector-class">.0</span>`。<br><br>在将缩放操作应用到&nbsp;<span class="hljs-selector-tag">Pod</span>&nbsp;之前，它前面的所有&nbsp;<span class="hljs-selector-tag">Pod</span>&nbsp;必须是&nbsp;<span class="hljs-selector-tag">Running</span>&nbsp;和&nbsp;<span class="hljs-selector-tag">Ready</span>&nbsp;状态。<br><br>在&nbsp;<span class="hljs-selector-tag">Pod</span>&nbsp;终止之前，所有的继任者必须完全关闭<br></code></pre>
        <p>创建或扩容过程，以Nginx举例</p>
        <pre><code class="hljs r">定义副本数replicas=<span class="hljs-number">3</span><br><br>SS会创建<span class="hljs-number">3</span>个Pod<br>分配有序序号<br>ng-<span class="hljs-number">0</span>,&nbsp;ng-<span class="hljs-number">1</span>,&nbsp;ng-<span class="hljs-number">2</span><br><br>SS严格执行部署或调度顺序，按序部署<br>ng-<span class="hljs-number">0</span>&nbsp;开始部署<span class="hljs-keyword">...</span><br>ng-<span class="hljs-number">0</span>&nbsp;进入Running&nbsp;和&nbsp;Ready&nbsp;状态<br><br>SS&nbsp;检测&nbsp;ng-<span class="hljs-number">0</span>&nbsp;部署状态<br>确定ng-<span class="hljs-number">0</span>，符合Running&nbsp;和&nbsp;Ready&nbsp;状态<br><br>ng-<span class="hljs-number">1</span>&nbsp;开始部署<br>ng-<span class="hljs-number">1</span>&nbsp;进入Running&nbsp;和&nbsp;Ready&nbsp;状态<br><br>SS&nbsp;检测&nbsp;ng-<span class="hljs-number">0</span>&nbsp;和&nbsp;ng-<span class="hljs-number">1</span>&nbsp;部署状态<br>确定ng-<span class="hljs-number">0</span>&nbsp;和&nbsp;ng-<span class="hljs-number">1</span>&nbsp;都符合Running&nbsp;和&nbsp;Ready&nbsp;状态<br>才会执行&nbsp;ng-<span class="hljs-number">2</span>&nbsp;部署<br><br>假设此时&nbsp;ng-<span class="hljs-number">0</span>&nbsp;发生故障<br>那么ng-<span class="hljs-number">2</span>&nbsp;会阻塞，等待&nbsp;ng-<span class="hljs-number">0</span>&nbsp;重新部署完成<br><br>ng-<span class="hljs-number">2</span>&nbsp;开始部署<br>ng-<span class="hljs-number">2</span>&nbsp;进入Running&nbsp;和&nbsp;Ready&nbsp;状态<br></code></pre>
        <p>类似，<code>StatefulSet</code> 进行缩容跟扩容整体规则是一样的，只不过缩容时，终止顺序和创建顺序<strong>相反</strong>。</p>
        <p>按照 <code>ng-2, ng-1, ng-0</code> 的顺序进行缩容操作。<code>ng-2</code>没有完全停止和删除前，ng-1不会进行终止操作。</p>
        <p><strong>注意：如果SS在缩容过程中，有些Pod发生了故障，那么终止会进入阻塞，等待发生故障的Pod重新调度，进入Running和Ready状态之后才会继续执行SS缩容。</strong></p>
        <h3 id="hstatefulsetpod"><span>针对线上StatefulSet 的Pod缩容故障无法正常缩容的情况，你能灰度分析一下嘛？</span></h3>
        <blockquote>
            <p>为什么缩容无法正常执行？</p>
        </blockquote>
        <p><code>StatefulSet</code> 执行缩容操作，<strong>需要保证管辖范围内的Pod处于健康状态</strong>。如果某些Pod<strong>发生故障，则缩容会陷入阻塞</strong>，无法继续执行。</p>
        <p>仅当 <code>StatefulSet</code> 等待到所有 Pod 都处于运<code>Running和 Ready</code> 状态后才可继续进行缩容操作。</p>
        <p><strong>了解完为什么缩容无法执行，那么再聊聊可能导致无法正常缩容原因都有哪些？</strong></p>
        <p>如果 <code>spec.replicas</code> 大于 1，Pod副本数量大于1 ，<code>Kubernetes</code> 无法直接判定 Pod 不健康的原因。</p>
        <p>Pod 不健康可能是由于<strong>永久性故障造成也可能是瞬态故障</strong>。 </p>
        <blockquote>
            <p>永久性故障</p>
        </blockquote>
        <p>如果该 Pod 不健康是由于永久性故障导致，则在不纠正该故障的情况下进行缩容可能会导致 <code>StatefulSet</code> <strong>成员 Pod 数量低于应正常运行的副本数</strong>。这种状态也许会导致 StatefulSet 不可用。</p>
        <blockquote>
            <p>瞬态故障</p>
        </blockquote>
        <p>瞬态故障可能是<strong>节点升级或维护而引起的节点重启</strong>造成的。</p>
        <p>如果由于瞬态故障而导致 Pod 不健康，一般情况下，Pod <strong>最终会再次变为可用</strong>，但是瞬态错误也可能会干扰 你对 <code>StatefulSet</code> 的扩容/缩容操作。 </p>
        <p>一些分布式数据库在同时有节点加入和离开时会遇到问题。</p>
        <p>在这些情况下，最好是在<strong>应用级别进行分析扩缩操作的状态</strong>，并且只有在确保 <code>Stateful</code> 应用的集群是完全健康时才执行扩缩操作。</p>
        <figure><img src="https://img-blog.csdnimg.cn/img_convert/96bdbea803ccc15c47ec4b1c77527d7d.gif" alt="" title=""><figcaption></figcaption></figure>
        <h3 id="hstatefulset"><span>聊聊什么是StatefulSet的分区滚动更新吧？什么场景可以使用分区更新？什么情况分区更新会失效？</span></h3>
        <p><strong>先说一下StatefulSet的更新策略</strong></p>
        <p><code>StatefulSet</code> 的 <code>.spec.updateStrategy</code> 字段可以配置和禁用掉自动滚动更新 Pod 的容器、标签、资源请求或限制、以及注解。</p>
        <p><code>spec.updateStrategy</code> 有两个允许的值：<code>RollingUpdate</code>和<code>OnDelete</code></p>
        <p><code>RollingUpdate</code> 更新策略</p>
        <pre><code class="hljs">对&nbsp;StatefulSet&nbsp;中的&nbsp;Pod&nbsp;执行自动的滚动更新。这是默认的更新策略<br></code></pre>
        <p><code>OnDelete</code>更新策略</p>
        <pre><code class="hljs css"><span class="hljs-selector-tag">StatefulSet</span>&nbsp;将不会自动更新&nbsp;<span class="hljs-selector-tag">StatefulSet</span>&nbsp;中的&nbsp;<span class="hljs-selector-tag">Pod</span><br><br>当<span class="hljs-selector-tag">StatefulSet</span>&nbsp;的&nbsp;<span class="hljs-selector-class">.spec</span><span class="hljs-selector-class">.template</span>&nbsp;设置出现变动<br>用户必须手动删除&nbsp;<span class="hljs-selector-tag">Pod</span>&nbsp;以便让控制器创建新的&nbsp;<span class="hljs-selector-tag">Pod</span><br></code></pre>
        <p><strong>滚动更新</strong></p>
        <p>当 <code>StatefulSet</code> 的 <code>.spec.updateStrategy.type</code> 被设置为 <code>RollingUpdate</code> 时， 属于默认滚动更新策略，这个时候如果template发生变化，StatefulSet 控制器会自动发起调度，进行删除和重建 <code>StatefulSet</code> 中的每个 Pod。 它将按照与 Pod 终止相同的顺序（从最大序号到最小序号）进行，每次更新一个 Pod。</p>
        <p>Kubernetes 控制面会等到被更新的 Pod 进入 <code>Running 和 Ready</code> 状态，然后再更新其前身Pod。 </p>
        <p>如果你设置了 <code>.spec.minReadySeconds</code>（最短就绪秒数），控制面在 Pod 就绪后会额外等待一定的时间再执行下一步。</p>
        <p><strong>接下来进入主题什么是分区滚动更新？</strong></p>
        <p>分区滚动更新是滚动更新策略中的一个特殊场景，StatefulSet 控制一定范围内的Pod进行滚动更新，调度为新版本Pod运行，而范围外的Pod继续维持老版本运行。</p>
        <p>可以理解为，学校16个班级，校长通知说："今天最后5个班级留下来打扫卫生"</p>
        <p>通过声明 <code>.spec.updateStrategy.rollingUpdate.partition</code> 的方式，<code>RollingUpdate</code> 更新策略可以实现分区。 </p>
        <p>如果声明了一个分区，当 StatefulSet 的 <code>.spec.template</code> 被更新时</p>
        <pre><code class="hljs">所有序号大于等于该分区序号的&nbsp;Pod&nbsp;都会被更新<br></code></pre>
        <pre><code class="hljs">所有序号小于该分区序号的&nbsp;Pod&nbsp;都不会被更新<br></code></pre>
        <p>分区更新，就是进行<strong>分段处理</strong>。</p>
        <pre><code class="hljs">假设原来有5个Pod<br>ng-0<br>ng-1<br>ng-2<br>ng-3<br>ng-4<br><br>SS滚动更新<br>ng-4&nbsp;更新<br>ng-3&nbsp;更新<br>ng-2&nbsp;更新<br>ng-1&nbsp;更新<br>ng-0&nbsp;更新<br><br>如果指定&nbsp;partition=2<br>那么SS执行滚动更新时<br>ng-4&nbsp;更新<br>ng-3&nbsp;更新<br>ng-2&nbsp;更新<br>ng-1&nbsp;不更新<br>ng-0&nbsp;不更新<br></code></pre>
        <p>需要注意的是，<strong>分区范围外的Pod</strong>，即使他们被删除或是重新调度，也会依据<strong>之前的旧版本进行重建</strong>，不会依赖当前最新版本重建。</p>
        <p>此外，如果 StatefulSet 的 <code>.spec.updateStrategy.rollingUpdate.partition</code> 大于它的 <code>.spec.replicas</code>，对它的 <code>.spec.template</code> 的更新将不会传递到它的 Pod，此时所谓分区更新将失去意义。</p>
        <p><strong>分区更新应用场景？</strong></p>
        <p>在大多数情况下，你不需要使用分区，但如果你希望进行<strong>阶段式更新、执行金丝雀或执行分阶段上线</strong>，则分区更新会非常有用。</p>
        <h3 id="hstatefulsetstatefulsetpod"><span>StatefulSet提供优雅稳定的存储，但是线上告警StatefulSet Pod重新调度后数据丢失？</span></h3>
        <p>究竟是什么情况呢？</p>
        <p>我们都知道k8s中当 <code>StatefulSet</code> 或者它管理的 Pod 被删除时并<strong>不会删除关联的卷</strong>，当重新调度完成后，新Pod应该会<strong>挂载原PV</strong>，继续使用上一个Pod的数据。</p>
        <p>坏事来了，本应该继续使用原PV，皆大欢喜，可是线上告警发现PV 持久卷无法使用，导致数据丢失。咦，失联了？？？</p>
        <p>k8s删除 <code>StatefulSet</code> 管理的 Pod 并不会删除关联的PV卷，这是为了确保你有机会重新调度Pod之后继续使用原PV卷，或者在删除卷之前从卷中复制数据，保证数据不会丢失。当一个 Pod 被调度（重新调度）到节点上时，它的 <code>volumeMounts</code> 会挂载与其 PVC相关联的 PV。</p>
        <p>删除StatefulSet 和Pod虽然不会删除关联的PV卷，但是删除PVC就不一定了，问题就出现在这里，在 Pod 离开终止状态后删除 PVC ，<strong>可能会触发删除背后的 PV 持久卷</strong>，具体触发策略要取决配置的存储类和回收策略。</p>
        <blockquote>
            <p>警告：⚠️ 永远不要假定在 PVC 删除后仍然能够访问卷</p>
            <p>警告：⚠️ 删除 PVC 时要谨慎，因为这可能会导致数据丢失</p>
        </blockquote>
        <figure><img src="https://img-blog.csdnimg.cn/img_convert/4d17e54f5bfc4009c5370acb2e7eb078.gif" alt="" title=""><figcaption></figcaption></figure>
        <blockquote>
            <p>获取更多干货（MySQL、K8S），欢迎关注微信公众号：囧么肥事</p>
        </blockquote></div></div>
    <!--content E-->
</div>



</body>
<!--left bar tools js S-->
<script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script>
<script type="text/javascript" src="../../static/js/nav.js"></script>
<!--left bar tools js E-->

<!-- 滚动条 S -->
<script type="text/javascript" src="../../static/js/optiscroll.js"></script>
<!-- 滚动条 E -->

<!--commonjs S-->
<script type="text/javascript" src="../../static/js/common.js"></script>
<!--commonjs E-->

</html>
